            .title  "Lab 5 - morse.asm"
;*******************************************************************************
;   CS/ECEn 124 Lab 5 - morse.asm: Student Code
;
;   Write a MSP430 assembler program that outputs a message in Morse Code on
;   the red LED and buzzer using a watchdog interrupt service routine (ISR).
;   Also, blink the eZ430 green LED on and off at one second intervals.
;
;   2 points    A Watchdog Timer interrupt service routine (ISR) is used to
;               blink the red and green LEDs and pulse the eZ430X buzzer.
;               Your program uses the .data section to pass variables between
;               your program and the Watchdog interrupt service routine (ISR).
;   2 points    The red LED blinks and the eZ430X buzzer makes an audible
;               sound for Morse Code dots and dashes to repeatedly output the
;               message "Hello World".
;   2 points    The International Morse Code standard is used to output your
;               message at a rate of 5 words per minute (DOTS are 1 element,
;               DASHES are 3 elements, 1 element between DOTS and DASHES,
;               3 elements in between each letter, and 7 elements in between words.)
;   2 points    The green LED continuously blinks on and off (toggles) every second.
;   2 points    The message "Hello World" is stored in program memory using the .byte
;               assembler directive and accessed using an indirect auto-increment
;               assembly instruction.
;
;
;   In addition to the above points, the following bonus/deductions apply:
;   1 point     Passed off with a TA at least one day early. (No timestamps please!)
;   1 point     The MSP430 enters low power mode until the Watchdog Timer ISR
;               finishes either a dot, dash or silent element.
;   1 point     Use a .string assembler directive to define the Morse Code message text.
;   1 point     By using a WPM assembly .set variable, reassemble your program
;               for 5, 10, or 20 words per minute.
;
;   Watchdog   MMB 8.1, pg. 276.
;   ISR's      MMB 6.8, pg. 190.
;
;   Description: Toggle P1.0 by xor'ing P1.0 inside of a software loop.
;   ACLK = n/a, MCLK = SMCLK = default DCO ~1.2MHz
;
;     A  P4.4     Left Pot  O--O  O  Servo #1
;     B  P4.5       Buzzer  O--O  O  Servo #2
;     C  P4.6   Thermistor  O  O--O  LED_4
;     D  P2.2  ADXL345 INT  O  O--O  SW_3
;     E  P2.3         SW_4  O--O  O  Servo #3
;     F  P2.4    Backlight  O--O  O  Servo #4
;     G  P4.3    Right Pot  O--O  O  EZ0_AN
;     H  P2.1         SW_2  O--O  O  EZ0_TX
;
;                MSP430F2274
;             -----------------
;            |                 |
;            |             P1.0|-->RED LED
;            |             P1.1|-->GREEN LED
;            |                 |
;            |             P4.5|-->BUZZER
;
;*******************************************************************************
            .nolist                         ; turn off list for headers
            .cdecls C,LIST,"msp430x22x4.h"  ; include c header
            .list                           ; turn list back on

myCLOCK     .set    1200000                 ; 1.2 Mhz clock

WDT_CLK     .set    500                     ; 500 Mhz WD clock (@1 Mhz)
WDT_CTL     .set    WDT_MDLY_0_5            ; WDT SMCLK, 0.5 ms
WDT_CPS     .set    myCLOCK/WDT_CLK         ; WD clocks / second count
STACK       .set    0x0600                  ; stack

END         .set    2
DOT         .set    1
DASH        .set    3
END_MESSAGE .set    4

WORDS       .set    5						; set words per minute
ELEMENTS    .set    50*WORDS				; this is how many elements in a minute
seconds     .set    60*1000*2				; number of miliseconds we want to wait
SPELE       .set    seconds/ELEMENTS          ; This is the time per element

HELLOWORLD
			.string DOT,DOT,DOT,END			; H
			.string	DOT,END					; E
			.string	DOT,DASH,DASH,DASH,END	; L
			.string	DOT,DASH,DASH,DASH,END	; L
			.string	DASH,DASH,DASH,END		; O
			.string	END_MESSAGE				; End word

			.string	DOT,DASH,DASH,END		; W
			.string	DASH,DASH,DASH,END		; O
			.string	DOT,DASH,DOT,END		; R
			.string	DOT,DASH,DASH,DASH,END  ; L
			.string	DASH,DOT,DOT,END		; D
			.string	END_MESSAGE,0			; End word
PARIS
			.string   DOT,DASH,DASH,DOT,END   ; P
            .string   DOT,DASH,END            ; A
            .string   DOT,DASH,DOT,END        ; R
            .string   DOT,DOT,END             ; I
            .string   DOT,DOT,DOT,END         ; S
            .string   END_MESSAGE       		; End word

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
            .data                           ; data section
            .bss    WDTSecCnt,2             ; WDT second counter
            .bss    audioplay,2

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
            .text                           ; program section
;   PARIS message
;message:
;			.byte   DOT,DASH,DASH,DOT,END   ; P
;            .byte   DOT,DASH,END            ; A
;            .byte   DOT,DASH,DOT,END        ; R
;            .byte   DOT,DOT,END             ; I
;            .byte   DOT,DOT,DOT,END         ; S
;            .byte   END_MESSAGE       		; End word
;            .align  2						; Align the message into bytes?

;helloworld:
;			.byte   DOT,DOT,DOT,END			; H
;			.byte	DOT,END					; E
;			.byte	DOT,DASH,DASH,DASH,END	; L
;			.byte	DOT,DASH,DASH,DASH,END	; L
;			.byte	DASH,DASH,DASH,END		; O
;			.byte	END_MESSAGE				; End word
;
;			.byte	DOT,DASH,DASH,END		; W
;			.byte	DASH,DASH,DASH,END		; O
;			.byte	DOT,DASH,DOT,END		; R
;			.byte	DOT,DASH,DASH,DASH,END  ; L
;			.byte	DASH,DOT,DOT,END		; D
;			.byte	END_MESSAGE,0			; End word
;			.align  2						; Align the message into bytes?


RESET:      mov.w   #STACK,SP               ; initialize stack pointer
            mov.w   #WDT_CTL,&WDTCTL        ; set WD timer interval
            mov.w   #WDT_CPS,&WDTSecCnt     ; initialize 1 sec WD counter
            mov.b   #WDTIE,&IE1             ; enable WDT interrupt

            bis.b   #0x20,&P4DIR            ; P4.5 output (transducer)
            bis.b   #0x03,&P1DIR            ; P1.0 output
            mov.b   #0,r13 					; play audio or not




start:
			mov.w   #HELLOWORLD,r4    		; Get address of first instruction

mainloop:
			cmp.w   #PARIS,r4				; if at next label
			  jge   start					; start the message over
			mov.b   @r4+,r5					; Get first element
		  	cmp.b   #END,r5					; If the element is an end
			  jeq   pause					; just a regular pause for one element
			cmp.b   #END_MESSAGE,r5			; if the element is a space between words
		  	  jeq   pause  					; just a regular pause for 4 elements

			call    #audioon				; if this is regular, call the audio
			jmp     pause					; add a pause after audio elements


audioon:
			bis.b   #1,&audioplay			; tell the watchdog to play audio

pause:
			call	#startloop				; pause for at least one element
			dec.b   r5						; if bigger than one
			   jl   mainloop				; return to main loop if we are negative
			  jnz   pause					; pause some more
			bit.b   #1,&audioplay			; test if we were playing an element
			  jeq   mainloop				; if not start again

endaudio:
			bic.b   #1,&audioplay			; else turn off audio
			ret								; return to whom called us


startloop:
			mov.w #SPELE,r6					; set the timer for element length

repeatloop:
			call    #gotosleep				; sleep once
            dec.w   r6                      ; Decrement by 1 Counter Loop
              jnz   repeatloop              ; Done n do it again
            ret								; return to whom called us


gotosleep:
			bis.w   #LPM0+GIE,SR            ; enable interrupts and go to sleep
            ret                             ; after watchdod cycles, return


;------------------------------------------------------------------------------
;   Watchdog Timer interrupt service routine
;
WDT_ISR:

            bit.w   #1,&audioplay      		; If we aren't supposed to play audio
              jeq   WDT_02                  ; skip the audio section
			bis.b   #0x01,&P1OUT            ; turn on red LED at P1.0
            xor.b   #0x20,&P4OUT            ; use 50% PWM

WDT_02:
			bic.w   #LPM0+GIE,0(SP)			; exit LPM0
			bic.b   #0x01,&P1OUT            ; toggle P1.0
			cmp.w   #200,&WDTSecCnt			; when we have 100 mSeconds left
			  jge   WDT_03					; if bigger, make sure green is off
			bis.b   #0x02,&P1OUT            ; turn on Green LED for a time
			jmp     WDT_04					; then skip turning off

WDT_03:
			bic.b   #0x02,&P1OUT            ; clear the green LED

WDT_04:
			dec.w   &WDTSecCnt              ; decrement counter, 0?
              jne   WDT_05                  ; n
            mov.w   #WDT_CPS,&WDTSecCnt     ; y, re-initialize counter


WDT_05:
			reti                            ; return from interrupt

;------------------------------------------------------------------------------
;           Interrupt Vectors
;------------------------------------------------------------------------------
            .sect   ".int10"                ; Watchdog Vector
            .word   WDT_ISR                 ; Watchdog ISR

            .sect   ".reset"                ; PUC Vector
            .word   RESET                   ; RESET ISR
            .end
